package ru.ifmo.itmokis.algo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import ru.ifmo.itmokis.domain.Material;
import ru.ifmo.itmokis.domain.OrderedProduct;
import ru.ifmo.itmokis.domain.Supply;
import ru.ifmo.itmokis.domain.Time;
import ru.ifmo.itmokis.util.DataContext;

/**
 *
 * @author Ivan Stepuk
 */
public class SupplyBuilder {

    public static final double K = 1.4;
    private DataContext dataContext;
    // ^ Dependencies ^
    private List<Supply> plan = new ArrayList<Supply>();

    public SupplyBuilder(DataContext dataContext) {

        this.dataContext = dataContext;
    }

    public void updatePlan(Material material, int qty) {
        Supply fresh = new Supply();
        fresh.setMaterial(material);
        fresh.setQty(qty);
        for (Supply supply : plan) {
            if (fresh.getMaterial().equals(supply.getMaterial())) {
                supply.setQty(supply.getQty() + fresh.getQty());
                return;
            }
        }
        plan.add(fresh);
    }

    public void updatePlan(Map<Material, Integer> rec) {
        Iterator<Entry<Material, Integer>> it = rec.entrySet().iterator();
        while (it.hasNext()) {
            Entry<Material, Integer> entry = it.next();
            updatePlan(entry.getKey(), entry.getValue());
        }
    }

    public void commitPlan(Time when) {
        // Update plan with stats
        List<OrderedProduct> history = dataContext.history(Time.ZERO, when);
        for (OrderedProduct op : history) {
            Map<Material, Integer> recipe = op.getProduct().getRecipe();
            Iterator<Entry<Material, Integer>> it = recipe.entrySet().iterator();
            while (it.hasNext()) {
                Entry<Material, Integer> entry = it.next();
                updatePlan(entry.getKey(), entry.getValue());
            }
        }
        for (Supply sup : plan) {
            sup.setQty((int) Math.ceil(
                    K * sup.getQty() / when.toPlainHours()
                    * (Time.WORK_HOURS * Time.WORK_DAYS)));
        }

        // Commit
        for (Supply supply : plan) {
            supply.setOrderTime(when);
            dataContext.persist(supply);
        }
        plan.clear();
    }
}
